{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "tdSnFaggnD2W"
   },
   "source": [
    "<a href=\"https://colab.research.google.com/github/jeffheaton/t81_558_deep_learning/blob/master/t81_558_class_10_2_lstm.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gc4uQ-bYnD2Y"
   },
   "source": [
    "# T81-558: Applications of Deep Neural Networks\n",
    "**Module 10: Time Series in Keras**\n",
    "* Instructor: [Jeff Heaton](https://sites.wustl.edu/jeffheaton/), McKelvey School of Engineering, [Washington University in St. Louis](https://engineering.wustl.edu/Programs/Pages/default.aspx)\n",
    "* For more information visit the [class website](https://sites.wustl.edu/jeffheaton/t81-558/)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QFj4U9c8nD2Y"
   },
   "source": [
    "# Module 10 Material\n",
    "\n",
    "* Part 10.1: Time Series Data Encoding for Deep Learning [[Video]](https://www.youtube.com/watch?v=dMUmHsktl04&list=PLjy4p-07OYzulelvJ5KVaT2pDlxivl_BN) [[Notebook]](https://github.com/jeffheaton/t81_558_deep_learning/blob/master/t81_558_class_10_1_timeseries.ipynb)\n",
    "* **Part 10.2: Programming LSTM with Keras and TensorFlow** [[Video]](https://www.youtube.com/watch?v=wY0dyFgNCgY&list=PLjy4p-07OYzulelvJ5KVaT2pDlxivl_BN) [[Notebook]](https://github.com/jeffheaton/t81_558_deep_learning/blob/master/t81_558_class_10_2_lstm.ipynb)\n",
    "* Part 10.3: Text Generation with Keras and TensorFlow [[Video]](https://www.youtube.com/watch?v=6ORnRAz3gnA&list=PLjy4p-07OYzulelvJ5KVaT2pDlxivl_BN) [[Notebook]](https://github.com/jeffheaton/t81_558_deep_learning/blob/master/t81_558_class_10_3_text_generation.ipynb)\n",
    "* Part 10.4: Introduction to Transformers [[Video]](https://www.youtube.com/watch?v=Z7FIdKVQ7kc&list=PLjy4p-07OYzulelvJ5KVaT2pDlxivl_BN) [[Notebook]](https://github.com/jeffheaton/t81_558_deep_learning/blob/master/t81_558_class_10_4_intro_transformers.ipynb)\n",
    "* Part 10.5: Transformers for Timeseries [[Video]](https://www.youtube.com/watch?v=SX67Mni0Or4&list=PLjy4p-07OYzulelvJ5KVaT2pDlxivl_BN) [[Notebook]](https://github.com/jeffheaton/t81_558_deep_learning/blob/master/t81_558_class_10_5_keras_transformers.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5MtBKuaZnD2Z"
   },
   "source": [
    "# Google CoLab Instructions\n",
    "\n",
    "The following code ensures that Google CoLab is running the correct version of TensorFlow.\n",
    "  Running the following code will map your GDrive to ```/content/drive```."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "nT6Wli6knD2Z",
    "outputId": "91564a14-b4c6-41e8-90bc-d62bbab8be8c"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mounted at /content/drive\n",
      "Note: using Google CoLab\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    from google.colab import drive\n",
    "    drive.mount('/content/drive', force_remount=True)\n",
    "    COLAB = True\n",
    "    print(\"Note: using Google CoLab\")\n",
    "    %tensorflow_version 2.x\n",
    "except:\n",
    "    print(\"Note: not using Google CoLab\")\n",
    "    COLAB = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_RH3-887nD2a"
   },
   "source": [
    "# Part 10.2: Programming LSTM with Keras and TensorFlow\n",
    "\n",
    "So far, the neural networks that we’ve examined have always had forward connections. Neural networks of this type always begin with an input layer connected to the first hidden layer. Each hidden layer always connects to the next hidden layer. The final hidden layer always connects to the output layer. This manner of connection is why these networks are called “feedforward.”  Recurrent neural networks are not as rigid, as backward linkages are also allowed. A recurrent connection links a neuron in a layer to either a previous layer or the neuron itself. Most recurrent neural network architectures maintain the state in the recurrent connections. Feedforward neural networks don’t keep any state. \n",
    "\n",
    "## Understanding LSTM\n",
    "\n",
    "Long Short Term Memory (LSTM) layers are a type of recurrent unit that you often use with deep neural networks.[[Cite:hochreiter1997long]](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.676.4320) For TensorFlow, you can think of LSTM as a layer type that you can combine with other layer types, such as dense. LSTM makes use of two transfer function types internally.  \n",
    "\n",
    "The first type of transfer function is the sigmoid.  This transfer function type is used form gates inside of the unit.  The sigmoid transfer function is given by the following equation:\n",
    "\n",
    "$ \\mbox{S}(t) = \\frac{1}{1 + e^{-t}} $\n",
    "\n",
    "The second type of transfer function is the hyperbolic tangent (tanh) function, which allows you to scale the output of the LSTM. This functionality is similar to how we have used other transfer functions in this course.  \n",
    "\n",
    "We provide the graphs for these functions here:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 548
    },
    "id": "aK4KCNPEnD2a",
    "outputId": "ea41b49e-8e52-4bcd-ce4e-42d1b2d8c9bd"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sigmoid\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hyperbolic Tangent(tanh)\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "import matplotlib\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import math\n",
    "\n",
    "def sigmoid(x):\n",
    "    a = []\n",
    "    for item in x:\n",
    "        a.append(1/(1+math.exp(-item)))\n",
    "    return a\n",
    "\n",
    "def f2(x):\n",
    "    a = []\n",
    "    for item in x:\n",
    "        a.append(math.tanh(item))\n",
    "    return a\n",
    "\n",
    "x = np.arange(-10., 10., 0.2)\n",
    "y1 = sigmoid(x)\n",
    "y2 = f2(x)\n",
    "\n",
    "print(\"Sigmoid\")\n",
    "plt.plot(x,y1)\n",
    "plt.show()\n",
    "\n",
    "print(\"Hyperbolic Tangent(tanh)\")\n",
    "plt.plot(x,y2)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "jyCPwHyfnD2b"
   },
   "source": [
    "Both of these two functions compress their output to a specific range.  For the sigmoid function, this range is 0 to 1.  For the hyperbolic tangent function, this range is -1 to 1.\n",
    "\n",
    "LSTM maintains an internal state and produces an output.  The following diagram shows an LSTM unit over three timeslices: the current time slice (t), as well as the previous (t-1) and next (t+1) slice, as demonstrated by Figure 10.LSTM.\n",
    "\n",
    "**Figure 10.LSTM: LSTM Layers**\n",
    "![LSTM Layers](https://raw.githubusercontent.com/jeffheaton/t81_558_deep_learning/master/images/class_10_lstm1.png \"LSTM Layers\")\n",
    "\n",
    "The values $\\hat{y}$ are the output from the unit; the values ($x$) are the input to the unit, and the values $c$ are the context values.  The output and context values always feed their output to the next time slice.  The context values allow the network to maintain the state between calls.  Figure 10.ILSTM shows the internals of a LSTM layer.\n",
    "\n",
    "**Figure 10.ILSTM: Inside a LSTM Layer**\n",
    "![LSTM Layers](https://raw.githubusercontent.com/jeffheaton/t81_558_deep_learning/master/images/class_10_lstm2.png \"Inside the LSTM\")\n",
    "\n",
    "A LSTM unit consists of three gates:\n",
    "\n",
    "* Forget Gate ($f_t$) - Controls if/when the context is forgotten. (MC)\n",
    "* Input Gate ($i_t$) - Controls if/when the context should remember a value. (M+/MS)\n",
    "* Output Gate ($o_t$) - Controls if/when the remembered value is allowed to pass from the unit. (RM)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "J0mVhDjAnD2c"
   },
   "source": [
    "## Simple Keras LSTM Example\n",
    "\n",
    "The following code creates the LSTM network, an example of an RNN for classification.  The following code trains on a data set (x) with a max sequence size of 6 (columns) and six training elements (rows)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "-lBrvaWKnD2c",
    "outputId": "6cb64779-fe1b-40ce-fdf6-c504d479a1bc"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0. 1. 0. 0.]\n",
      " [0. 0. 1. 0.]\n",
      " [0. 0. 0. 1.]\n",
      " [0. 0. 1. 0.]\n",
      " [0. 0. 0. 1.]\n",
      " [0. 1. 0. 0.]]\n",
      "Build model...\n",
      "Train...\n",
      "Epoch 1/200\n",
      "1/1 [==============================] - 6s 6s/step - loss: 0.6885 - accuracy: 0.3333\n",
      "Epoch 2/200\n",
      "1/1 [==============================] - 0s 45ms/step - loss: 0.6807 - accuracy: 0.3333\n",
      "Epoch 3/200\n",
      "1/1 [==============================] - 0s 38ms/step - loss: 0.6773 - accuracy: 0.3333\n",
      "Epoch 4/200\n",
      "1/1 [==============================] - 0s 37ms/step - loss: 0.6684 - accuracy: 0.3333\n",
      "Epoch 5/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.6556 - accuracy: 0.3333\n",
      "Epoch 6/200\n",
      "1/1 [==============================] - 0s 37ms/step - loss: 0.6555 - accuracy: 0.3333\n",
      "Epoch 7/200\n",
      "1/1 [==============================] - 0s 31ms/step - loss: 0.6397 - accuracy: 0.1667\n",
      "Epoch 8/200\n",
      "1/1 [==============================] - 0s 40ms/step - loss: 0.6376 - accuracy: 0.3333\n",
      "Epoch 9/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.6302 - accuracy: 0.3333\n",
      "Epoch 10/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.6217 - accuracy: 0.5000\n",
      "Epoch 11/200\n",
      "1/1 [==============================] - 0s 52ms/step - loss: 0.6196 - accuracy: 0.6667\n",
      "Epoch 12/200\n",
      "1/1 [==============================] - 0s 41ms/step - loss: 0.6009 - accuracy: 0.5000\n",
      "Epoch 13/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.6049 - accuracy: 0.3333\n",
      "Epoch 14/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.5894 - accuracy: 0.3333\n",
      "Epoch 15/200\n",
      "1/1 [==============================] - 0s 23ms/step - loss: 0.5853 - accuracy: 0.3333\n",
      "Epoch 16/200\n",
      "1/1 [==============================] - 0s 31ms/step - loss: 0.5648 - accuracy: 0.3333\n",
      "Epoch 17/200\n",
      "1/1 [==============================] - 0s 51ms/step - loss: 0.5497 - accuracy: 0.3333\n",
      "Epoch 18/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.5413 - accuracy: 0.3333\n",
      "Epoch 19/200\n",
      "1/1 [==============================] - 0s 70ms/step - loss: 0.5429 - accuracy: 0.3333\n",
      "Epoch 20/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.5217 - accuracy: 0.3333\n",
      "Epoch 21/200\n",
      "1/1 [==============================] - 0s 53ms/step - loss: 0.5304 - accuracy: 0.3333\n",
      "Epoch 22/200\n",
      "1/1 [==============================] - 0s 58ms/step - loss: 0.5332 - accuracy: 0.3333\n",
      "Epoch 23/200\n",
      "1/1 [==============================] - 0s 52ms/step - loss: 0.5090 - accuracy: 0.3333\n",
      "Epoch 24/200\n",
      "1/1 [==============================] - 0s 55ms/step - loss: 0.5055 - accuracy: 0.3333\n",
      "Epoch 25/200\n",
      "1/1 [==============================] - 0s 47ms/step - loss: 0.5020 - accuracy: 0.3333\n",
      "Epoch 26/200\n",
      "1/1 [==============================] - 0s 47ms/step - loss: 0.5224 - accuracy: 0.1667\n",
      "Epoch 27/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.5060 - accuracy: 0.1667\n",
      "Epoch 28/200\n",
      "1/1 [==============================] - 0s 50ms/step - loss: 0.5123 - accuracy: 0.1667\n",
      "Epoch 29/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.4740 - accuracy: 0.5000\n",
      "Epoch 30/200\n",
      "1/1 [==============================] - 0s 40ms/step - loss: 0.5018 - accuracy: 0.3333\n",
      "Epoch 31/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.4982 - accuracy: 0.3333\n",
      "Epoch 32/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.4640 - accuracy: 0.3333\n",
      "Epoch 33/200\n",
      "1/1 [==============================] - 0s 47ms/step - loss: 0.4748 - accuracy: 0.5000\n",
      "Epoch 34/200\n",
      "1/1 [==============================] - 0s 50ms/step - loss: 0.4593 - accuracy: 0.5000\n",
      "Epoch 35/200\n",
      "1/1 [==============================] - 0s 47ms/step - loss: 0.4712 - accuracy: 0.3333\n",
      "Epoch 36/200\n",
      "1/1 [==============================] - 0s 47ms/step - loss: 0.4444 - accuracy: 0.5000\n",
      "Epoch 37/200\n",
      "1/1 [==============================] - 0s 46ms/step - loss: 0.4651 - accuracy: 0.5000\n",
      "Epoch 38/200\n",
      "1/1 [==============================] - 0s 41ms/step - loss: 0.4582 - accuracy: 0.5000\n",
      "Epoch 39/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.4191 - accuracy: 0.5000\n",
      "Epoch 40/200\n",
      "1/1 [==============================] - 0s 45ms/step - loss: 0.4470 - accuracy: 0.5000\n",
      "Epoch 41/200\n",
      "1/1 [==============================] - 0s 79ms/step - loss: 0.4258 - accuracy: 0.5000\n",
      "Epoch 42/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.4161 - accuracy: 0.6667\n",
      "Epoch 43/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.4094 - accuracy: 0.6667\n",
      "Epoch 44/200\n",
      "1/1 [==============================] - 0s 25ms/step - loss: 0.4246 - accuracy: 0.6667\n",
      "Epoch 45/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.4377 - accuracy: 0.3333\n",
      "Epoch 46/200\n",
      "1/1 [==============================] - 0s 37ms/step - loss: 0.4404 - accuracy: 0.3333\n",
      "Epoch 47/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.4526 - accuracy: 0.3333\n",
      "Epoch 48/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.4009 - accuracy: 0.8333\n",
      "Epoch 49/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.4128 - accuracy: 0.5000\n",
      "Epoch 50/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.3961 - accuracy: 0.6667\n",
      "Epoch 51/200\n",
      "1/1 [==============================] - 0s 36ms/step - loss: 0.4152 - accuracy: 0.6667\n",
      "Epoch 52/200\n",
      "1/1 [==============================] - 0s 31ms/step - loss: 0.3690 - accuracy: 0.8333\n",
      "Epoch 53/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.4025 - accuracy: 0.6667\n",
      "Epoch 54/200\n",
      "1/1 [==============================] - 0s 40ms/step - loss: 0.3933 - accuracy: 0.6667\n",
      "Epoch 55/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.4072 - accuracy: 0.8333\n",
      "Epoch 56/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.4008 - accuracy: 0.6667\n",
      "Epoch 57/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.3789 - accuracy: 0.6667\n",
      "Epoch 58/200\n",
      "1/1 [==============================] - 0s 51ms/step - loss: 0.3937 - accuracy: 0.6667\n",
      "Epoch 59/200\n",
      "1/1 [==============================] - 0s 36ms/step - loss: 0.3516 - accuracy: 0.6667\n",
      "Epoch 60/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.3525 - accuracy: 0.8333\n",
      "Epoch 61/200\n",
      "1/1 [==============================] - 0s 31ms/step - loss: 0.3484 - accuracy: 1.0000\n",
      "Epoch 62/200\n",
      "1/1 [==============================] - 0s 53ms/step - loss: 0.3067 - accuracy: 0.8333\n",
      "Epoch 63/200\n",
      "1/1 [==============================] - 0s 40ms/step - loss: 0.3600 - accuracy: 0.5000\n",
      "Epoch 64/200\n",
      "1/1 [==============================] - 0s 37ms/step - loss: 0.4628 - accuracy: 0.1667\n",
      "Epoch 65/200\n",
      "1/1 [==============================] - 0s 62ms/step - loss: 0.4443 - accuracy: 0.5000\n",
      "Epoch 66/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.3164 - accuracy: 0.8333\n",
      "Epoch 67/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.3303 - accuracy: 0.8333\n",
      "Epoch 68/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.3264 - accuracy: 0.8333\n",
      "Epoch 69/200\n",
      "1/1 [==============================] - 0s 29ms/step - loss: 0.3518 - accuracy: 0.5000\n",
      "Epoch 70/200\n",
      "1/1 [==============================] - 0s 27ms/step - loss: 0.2797 - accuracy: 0.8333\n",
      "Epoch 71/200\n",
      "1/1 [==============================] - 0s 29ms/step - loss: 0.3595 - accuracy: 0.5000\n",
      "Epoch 72/200\n",
      "1/1 [==============================] - 0s 29ms/step - loss: 0.3141 - accuracy: 0.6667\n",
      "Epoch 73/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.2957 - accuracy: 0.8333\n",
      "Epoch 74/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.3181 - accuracy: 0.8333\n",
      "Epoch 75/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.3049 - accuracy: 0.6667\n",
      "Epoch 76/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.3390 - accuracy: 0.6667\n",
      "Epoch 77/200\n",
      "1/1 [==============================] - 0s 31ms/step - loss: 0.3328 - accuracy: 0.6667\n",
      "Epoch 78/200\n",
      "1/1 [==============================] - 0s 41ms/step - loss: 0.3262 - accuracy: 0.6667\n",
      "Epoch 79/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.2353 - accuracy: 0.8333\n",
      "Epoch 80/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.3484 - accuracy: 0.6667\n",
      "Epoch 81/200\n",
      "1/1 [==============================] - 0s 26ms/step - loss: 0.4174 - accuracy: 0.6667\n",
      "Epoch 82/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.2780 - accuracy: 0.8333\n",
      "Epoch 83/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.3406 - accuracy: 0.5000\n",
      "Epoch 84/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.2736 - accuracy: 0.6667\n",
      "Epoch 85/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.3383 - accuracy: 0.6667\n",
      "Epoch 86/200\n",
      "1/1 [==============================] - 0s 51ms/step - loss: 0.3119 - accuracy: 0.6667\n",
      "Epoch 87/200\n",
      "1/1 [==============================] - 0s 21ms/step - loss: 0.5429 - accuracy: 0.3333\n",
      "Epoch 88/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.2317 - accuracy: 0.8333\n",
      "Epoch 89/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.4463 - accuracy: 0.5000\n",
      "Epoch 90/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.3199 - accuracy: 0.6667\n",
      "Epoch 91/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.2997 - accuracy: 0.8333\n",
      "Epoch 92/200\n",
      "1/1 [==============================] - 0s 53ms/step - loss: 0.3121 - accuracy: 0.8333\n",
      "Epoch 93/200\n",
      "1/1 [==============================] - 0s 24ms/step - loss: 0.3872 - accuracy: 0.5000\n",
      "Epoch 94/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.3367 - accuracy: 0.5000\n",
      "Epoch 95/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.3248 - accuracy: 0.6667\n",
      "Epoch 96/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.3325 - accuracy: 0.6667\n",
      "Epoch 97/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.3257 - accuracy: 0.6667\n",
      "Epoch 98/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.3003 - accuracy: 0.6667\n",
      "Epoch 99/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.3220 - accuracy: 0.6667\n",
      "Epoch 100/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.2347 - accuracy: 0.8333\n",
      "Epoch 101/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.3386 - accuracy: 0.6667\n",
      "Epoch 102/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.3677 - accuracy: 0.5000\n",
      "Epoch 103/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.2826 - accuracy: 0.6667\n",
      "Epoch 104/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.3603 - accuracy: 0.6667\n",
      "Epoch 105/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.2047 - accuracy: 0.8333\n",
      "Epoch 106/200\n",
      "1/1 [==============================] - 0s 36ms/step - loss: 0.2239 - accuracy: 0.8333\n",
      "Epoch 107/200\n",
      "1/1 [==============================] - 0s 62ms/step - loss: 0.2280 - accuracy: 0.8333\n",
      "Epoch 108/200\n",
      "1/1 [==============================] - 0s 34ms/step - loss: 0.2398 - accuracy: 0.8333\n",
      "Epoch 109/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.2423 - accuracy: 0.8333\n",
      "Epoch 110/200\n",
      "1/1 [==============================] - 0s 25ms/step - loss: 0.2059 - accuracy: 0.8333\n",
      "Epoch 111/200\n",
      "1/1 [==============================] - 0s 28ms/step - loss: 0.3120 - accuracy: 0.6667\n",
      "Epoch 112/200\n",
      "1/1 [==============================] - 0s 29ms/step - loss: 0.5211 - accuracy: 0.5000\n",
      "Epoch 113/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.2082 - accuracy: 0.8333\n",
      "Epoch 114/200\n",
      "1/1 [==============================] - 0s 47ms/step - loss: 0.2927 - accuracy: 0.6667\n",
      "Epoch 115/200\n",
      "1/1 [==============================] - 0s 48ms/step - loss: 0.2020 - accuracy: 0.8333\n",
      "Epoch 116/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.3345 - accuracy: 0.6667\n",
      "Epoch 117/200\n",
      "1/1 [==============================] - 0s 38ms/step - loss: 0.1803 - accuracy: 0.8333\n",
      "Epoch 118/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.1741 - accuracy: 0.8333\n",
      "Epoch 119/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.3439 - accuracy: 0.5000\n",
      "Epoch 120/200\n",
      "1/1 [==============================] - 0s 48ms/step - loss: 0.3067 - accuracy: 0.5000\n",
      "Epoch 121/200\n",
      "1/1 [==============================] - 0s 54ms/step - loss: 0.2623 - accuracy: 0.6667\n",
      "Epoch 122/200\n",
      "1/1 [==============================] - 0s 38ms/step - loss: 0.2178 - accuracy: 0.6667\n",
      "Epoch 123/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.2032 - accuracy: 0.8333\n",
      "Epoch 124/200\n",
      "1/1 [==============================] - 0s 49ms/step - loss: 0.2357 - accuracy: 0.6667\n",
      "Epoch 125/200\n",
      "1/1 [==============================] - 0s 28ms/step - loss: 0.2624 - accuracy: 0.8333\n",
      "Epoch 126/200\n",
      "1/1 [==============================] - 0s 41ms/step - loss: 0.2712 - accuracy: 0.6667\n",
      "Epoch 127/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.2747 - accuracy: 0.6667\n",
      "Epoch 128/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.2485 - accuracy: 0.6667\n",
      "Epoch 129/200\n",
      "1/1 [==============================] - 0s 23ms/step - loss: 0.2423 - accuracy: 0.6667\n",
      "Epoch 130/200\n",
      "1/1 [==============================] - 0s 36ms/step - loss: 0.2219 - accuracy: 0.6667\n",
      "Epoch 131/200\n",
      "1/1 [==============================] - 0s 59ms/step - loss: 0.4338 - accuracy: 0.6667\n",
      "Epoch 132/200\n",
      "1/1 [==============================] - 0s 48ms/step - loss: 0.1960 - accuracy: 0.6667\n",
      "Epoch 133/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.4131 - accuracy: 0.8333\n",
      "Epoch 134/200\n",
      "1/1 [==============================] - 0s 37ms/step - loss: 0.2598 - accuracy: 0.8333\n",
      "Epoch 135/200\n",
      "1/1 [==============================] - 0s 31ms/step - loss: 0.3850 - accuracy: 0.6667\n",
      "Epoch 136/200\n",
      "1/1 [==============================] - 0s 41ms/step - loss: 0.5136 - accuracy: 0.5000\n",
      "Epoch 137/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.1772 - accuracy: 0.8333\n",
      "Epoch 138/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.3608 - accuracy: 0.5000\n",
      "Epoch 139/200\n",
      "1/1 [==============================] - 0s 36ms/step - loss: 0.4406 - accuracy: 0.6667\n",
      "Epoch 140/200\n",
      "1/1 [==============================] - 0s 30ms/step - loss: 0.1779 - accuracy: 0.8333\n",
      "Epoch 141/200\n",
      "1/1 [==============================] - 0s 50ms/step - loss: 0.2793 - accuracy: 0.6667\n",
      "Epoch 142/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.4084 - accuracy: 0.6667\n",
      "Epoch 143/200\n",
      "1/1 [==============================] - 0s 44ms/step - loss: 0.2198 - accuracy: 0.8333\n",
      "Epoch 144/200\n",
      "1/1 [==============================] - 0s 66ms/step - loss: 0.2510 - accuracy: 0.6667\n",
      "Epoch 145/200\n",
      "1/1 [==============================] - 0s 60ms/step - loss: 0.2303 - accuracy: 0.8333\n",
      "Epoch 146/200\n",
      "1/1 [==============================] - 0s 46ms/step - loss: 0.1859 - accuracy: 0.8333\n",
      "Epoch 147/200\n",
      "1/1 [==============================] - 0s 46ms/step - loss: 0.2167 - accuracy: 1.0000\n",
      "Epoch 148/200\n",
      "1/1 [==============================] - 0s 40ms/step - loss: 0.2193 - accuracy: 0.6667\n",
      "Epoch 149/200\n",
      "1/1 [==============================] - 0s 32ms/step - loss: 0.3893 - accuracy: 0.5000\n",
      "Epoch 150/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.1955 - accuracy: 0.8333\n",
      "Epoch 151/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.2113 - accuracy: 1.0000\n",
      "Epoch 152/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.1952 - accuracy: 0.8333\n",
      "Epoch 153/200\n",
      "1/1 [==============================] - 0s 31ms/step - loss: 0.2329 - accuracy: 0.6667\n",
      "Epoch 154/200\n",
      "1/1 [==============================] - 0s 41ms/step - loss: 0.2074 - accuracy: 0.8333\n",
      "Epoch 155/200\n",
      "1/1 [==============================] - 0s 36ms/step - loss: 0.2839 - accuracy: 0.6667\n",
      "Epoch 156/200\n",
      "1/1 [==============================] - 0s 40ms/step - loss: 0.2847 - accuracy: 0.6667\n",
      "Epoch 157/200\n",
      "1/1 [==============================] - 0s 37ms/step - loss: 0.1876 - accuracy: 0.8333\n",
      "Epoch 158/200\n",
      "1/1 [==============================] - 0s 51ms/step - loss: 0.3081 - accuracy: 0.6667\n",
      "Epoch 159/200\n",
      "1/1 [==============================] - 0s 46ms/step - loss: 0.2110 - accuracy: 0.8333\n",
      "Epoch 160/200\n",
      "1/1 [==============================] - 0s 51ms/step - loss: 0.1817 - accuracy: 1.0000\n",
      "Epoch 161/200\n",
      "1/1 [==============================] - 0s 45ms/step - loss: 0.2173 - accuracy: 0.8333\n",
      "Epoch 162/200\n",
      "1/1 [==============================] - 0s 51ms/step - loss: 0.1674 - accuracy: 0.8333\n",
      "Epoch 163/200\n",
      "1/1 [==============================] - 0s 48ms/step - loss: 0.2233 - accuracy: 0.6667\n",
      "Epoch 164/200\n",
      "1/1 [==============================] - 0s 52ms/step - loss: 0.2647 - accuracy: 0.6667\n",
      "Epoch 165/200\n",
      "1/1 [==============================] - 0s 50ms/step - loss: 0.2601 - accuracy: 0.8333\n",
      "Epoch 166/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.2574 - accuracy: 0.6667\n",
      "Epoch 167/200\n",
      "1/1 [==============================] - 0s 54ms/step - loss: 0.1954 - accuracy: 1.0000\n",
      "Epoch 168/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.1537 - accuracy: 1.0000\n",
      "Epoch 169/200\n",
      "1/1 [==============================] - 0s 45ms/step - loss: 0.1472 - accuracy: 1.0000\n",
      "Epoch 170/200\n",
      "1/1 [==============================] - 0s 52ms/step - loss: 0.2924 - accuracy: 0.8333\n",
      "Epoch 171/200\n",
      "1/1 [==============================] - 0s 47ms/step - loss: 0.2536 - accuracy: 0.8333\n",
      "Epoch 172/200\n",
      "1/1 [==============================] - 0s 58ms/step - loss: 0.3378 - accuracy: 0.6667\n",
      "Epoch 173/200\n",
      "1/1 [==============================] - 0s 57ms/step - loss: 0.2863 - accuracy: 0.6667\n",
      "Epoch 174/200\n",
      "1/1 [==============================] - 0s 49ms/step - loss: 0.2654 - accuracy: 0.6667\n",
      "Epoch 175/200\n",
      "1/1 [==============================] - 0s 50ms/step - loss: 0.3798 - accuracy: 0.6667\n",
      "Epoch 176/200\n",
      "1/1 [==============================] - 0s 52ms/step - loss: 0.2439 - accuracy: 0.8333\n",
      "Epoch 177/200\n",
      "1/1 [==============================] - 0s 52ms/step - loss: 0.2164 - accuracy: 0.8333\n",
      "Epoch 178/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.2440 - accuracy: 0.8333\n",
      "Epoch 179/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.2581 - accuracy: 0.6667\n",
      "Epoch 180/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.2226 - accuracy: 0.8333\n",
      "Epoch 181/200\n",
      "1/1 [==============================] - 0s 38ms/step - loss: 0.2108 - accuracy: 0.8333\n",
      "Epoch 182/200\n",
      "1/1 [==============================] - 0s 51ms/step - loss: 0.1613 - accuracy: 0.8333\n",
      "Epoch 183/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.1548 - accuracy: 0.8333\n",
      "Epoch 184/200\n",
      "1/1 [==============================] - 0s 58ms/step - loss: 0.4014 - accuracy: 0.6667\n",
      "Epoch 185/200\n",
      "1/1 [==============================] - 0s 41ms/step - loss: 0.1978 - accuracy: 1.0000\n",
      "Epoch 186/200\n",
      "1/1 [==============================] - 0s 63ms/step - loss: 0.3166 - accuracy: 0.8333\n",
      "Epoch 187/200\n",
      "1/1 [==============================] - 0s 42ms/step - loss: 0.1714 - accuracy: 1.0000\n",
      "Epoch 188/200\n",
      "1/1 [==============================] - 0s 38ms/step - loss: 0.1819 - accuracy: 0.8333\n",
      "Epoch 189/200\n",
      "1/1 [==============================] - 0s 33ms/step - loss: 0.3144 - accuracy: 0.6667\n",
      "Epoch 190/200\n",
      "1/1 [==============================] - 0s 35ms/step - loss: 0.2543 - accuracy: 0.8333\n",
      "Epoch 191/200\n",
      "1/1 [==============================] - 0s 58ms/step - loss: 0.3698 - accuracy: 0.6667\n",
      "Epoch 192/200\n",
      "1/1 [==============================] - 0s 29ms/step - loss: 0.2331 - accuracy: 0.6667\n",
      "Epoch 193/200\n",
      "1/1 [==============================] - 0s 37ms/step - loss: 0.3119 - accuracy: 0.8333\n",
      "Epoch 194/200\n",
      "1/1 [==============================] - 0s 43ms/step - loss: 0.2397 - accuracy: 0.8333\n",
      "Epoch 195/200\n",
      "1/1 [==============================] - 0s 54ms/step - loss: 0.4169 - accuracy: 0.6667\n",
      "Epoch 196/200\n",
      "1/1 [==============================] - 0s 36ms/step - loss: 0.2346 - accuracy: 0.8333\n",
      "Epoch 197/200\n",
      "1/1 [==============================] - 0s 81ms/step - loss: 0.1831 - accuracy: 0.8333\n",
      "Epoch 198/200\n",
      "1/1 [==============================] - 0s 45ms/step - loss: 0.2516 - accuracy: 0.8333\n",
      "Epoch 199/200\n",
      "1/1 [==============================] - 0s 66ms/step - loss: 0.2622 - accuracy: 0.6667\n",
      "Epoch 200/200\n",
      "1/1 [==============================] - 0s 39ms/step - loss: 0.2329 - accuracy: 0.6667\n",
      "Predicted classes: {} [1 2 3 2 3 1]\n",
      "Expected classes: {} [1 2 3 2 3 1]\n"
     ]
    }
   ],
   "source": [
    "from tensorflow.keras.preprocessing import sequence\n",
    "from tensorflow.keras.models import Sequential\n",
    "from tensorflow.keras.layers import Dense, Embedding\n",
    "from tensorflow.keras.layers import LSTM\n",
    "import numpy as np\n",
    "\n",
    "max_features = 4 # 0,1,2,3 (total of 4)\n",
    "x = [\n",
    "    [[0],[1],[1],[0],[0],[0]],\n",
    "    [[0],[0],[0],[2],[2],[0]],\n",
    "    [[0],[0],[0],[0],[3],[3]],\n",
    "    [[0],[2],[2],[0],[0],[0]],\n",
    "    [[0],[0],[3],[3],[0],[0]],\n",
    "    [[0],[0],[0],[0],[1],[1]]\n",
    "]\n",
    "x = np.array(x,dtype=np.float32)\n",
    "y = np.array([1,2,3,2,3,1],dtype=np.int32)\n",
    "\n",
    "# Convert y2 to dummy variables\n",
    "y2 = np.zeros((y.shape[0], max_features),dtype=np.float32)\n",
    "y2[np.arange(y.shape[0]), y] = 1.0\n",
    "print(y2)\n",
    "\n",
    "print('Build model...')\n",
    "model = Sequential()\n",
    "model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2, \\\n",
    "               input_shape=(None, 1)))\n",
    "model.add(Dense(4, activation='sigmoid'))\n",
    "\n",
    "# try using different optimizers and different optimizer configs\n",
    "model.compile(loss='binary_crossentropy',\n",
    "              optimizer='adam',\n",
    "              metrics=['accuracy'])\n",
    "\n",
    "print('Train...')\n",
    "model.fit(x,y2,epochs=200)\n",
    "pred = model.predict(x)\n",
    "predict_classes = np.argmax(pred,axis=1)\n",
    "print(\"Predicted classes: {}\",predict_classes)\n",
    "print(\"Expected classes: {}\",y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CMIZvStnnD2c"
   },
   "source": [
    "We can now present a sequence directly to the model for classification."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "F3otdNdwnD2d",
    "outputId": "b459b33f-4c47-4b87-cb6e-59a35e410455"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "def runit(model, inp):\n",
    "    inp = np.array(inp,dtype=np.float32)\n",
    "    pred = model.predict(inp)\n",
    "    return np.argmax(pred[0])\n",
    "\n",
    "print( runit( model, [[[0],[0],[0],[0],[0],[1]]] ))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1DfNO5l8nD2d"
   },
   "source": [
    "## Sun Spots Example\n",
    "\n",
    "This section shows an example of RNN regression to predict sunspots.  You can find the data files needed for this example at the following location.\n",
    "\n",
    "* [Sunspot Data Files](http://www.sidc.be/silso/datafiles#total)\n",
    "* [Download Daily Sunspots](http://www.sidc.be/silso/INFO/sndtotcsv.php) - 1/1/1818 to now.\n",
    "\n",
    "The following code loads the sunspot file:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "c561r7ZCnD2d",
    "outputId": "c66d96d8-f902-4944-e7e9-05b2786816e0"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting file:\n",
      "   year  month  day  dec_year  sn_value  sn_error  obs_num  unused1\n",
      "0  1818      1    1  1818.001        -1       NaN        0        1\n",
      "1  1818      1    2  1818.004        -1       NaN        0        1\n",
      "2  1818      1    3  1818.007        -1       NaN        0        1\n",
      "3  1818      1    4  1818.010        -1       NaN        0        1\n",
      "4  1818      1    5  1818.012        -1       NaN        0        1\n",
      "5  1818      1    6  1818.015        -1       NaN        0        1\n",
      "6  1818      1    7  1818.018        -1       NaN        0        1\n",
      "7  1818      1    8  1818.021        65      10.2        1        1\n",
      "8  1818      1    9  1818.023        -1       NaN        0        1\n",
      "9  1818      1   10  1818.026        -1       NaN        0        1\n",
      "Ending file:\n",
      "       year  month  day  dec_year  sn_value  sn_error  obs_num  unused1\n",
      "72855  2017      6   21  2017.470        35       1.0       41        0\n",
      "72856  2017      6   22  2017.473        24       0.8       39        0\n",
      "72857  2017      6   23  2017.475        23       0.9       40        0\n",
      "72858  2017      6   24  2017.478        26       2.3       15        0\n",
      "72859  2017      6   25  2017.481        17       1.0       18        0\n",
      "72860  2017      6   26  2017.484        21       1.1       25        0\n",
      "72861  2017      6   27  2017.486        19       1.2       36        0\n",
      "72862  2017      6   28  2017.489        17       1.1       22        0\n",
      "72863  2017      6   29  2017.492        12       0.5       25        0\n",
      "72864  2017      6   30  2017.495        11       0.5       30        0\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import os\n",
    "  \n",
    "names = ['year', 'month', 'day', 'dec_year', 'sn_value' , \n",
    "         'sn_error', 'obs_num', 'unused1']\n",
    "df = pd.read_csv(\n",
    "    \"https://data.heatonresearch.com/data/t81-558/SN_d_tot_V2.0.csv\",\n",
    "    sep=';',header=None,names=names,\n",
    "    na_values=['-1'], index_col=False)\n",
    "\n",
    "print(\"Starting file:\")\n",
    "print(df[0:10])\n",
    "\n",
    "print(\"Ending file:\")\n",
    "print(df[-10:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9R3-vBANnD2d"
   },
   "source": [
    "As you can see, there is quite a bit of missing data near the end of the file.  We want to find the starting index where the missing data no longer occurs.  This technique is somewhat sloppy; it would be better to find a use for the data between missing values.  However, the point of this example is to show how to use LSTM with a somewhat simple time-series."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "mT-4MgobnD2d",
    "outputId": "76939195-fea1-47f4-bc84-53b52900e286"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11314\n"
     ]
    }
   ],
   "source": [
    "start_id = max(df[df['obs_num'] == 0].index.tolist())+1  # Find the last zero and move one beyond\n",
    "print(start_id)\n",
    "df = df[start_id:] # Trim the rows that have missing observations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "8oL8-qB2nD2e",
    "outputId": "ba74ef8c-a289-4e6e-f828-dd7f92cf03a0"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training set has 55160 observations.\n",
      "Test set has 6391 observations.\n"
     ]
    }
   ],
   "source": [
    "df['sn_value'] = df['sn_value'].astype(float)\n",
    "df_train = df[df['year']<2000]\n",
    "df_test = df[df['year']>=2000]\n",
    "\n",
    "spots_train = df_train['sn_value'].tolist()\n",
    "spots_test = df_test['sn_value'].tolist()\n",
    "\n",
    "print(\"Training set has {} observations.\".format(len(spots_train)))\n",
    "print(\"Test set has {} observations.\".format(len(spots_test)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ipM_LjwxnD2e"
   },
   "source": [
    "To create an algorithm that will predict future values, we need to consider how to encode this data to be presented to the algorithm. The data must be submitted as sequences, using a sliding window algorithm to encode the data. We must define how large the window will be. Consider an n-sized window. Each sequence's $x$ values will be a $n$ data points sequence. The $y$'s will be the next value, after the sequence, that we are trying to predict. You can use the following function to take a series of values, such as sunspots, and generate sequences ($x$) and predicted values ($y$)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "kyUII6JynD2e",
    "outputId": "ab0fecf3-5f98-4d65-c234-a017d06f2c51"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shape of training set: (55150, 10, 1)\n",
      "Shape of test set: (6381, 10, 1)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "def to_sequences(seq_size, obs):\n",
    "    x = []\n",
    "    y = []\n",
    "\n",
    "    for i in range(len(obs)-SEQUENCE_SIZE):\n",
    "        #print(i)\n",
    "        window = obs[i:(i+SEQUENCE_SIZE)]\n",
    "        after_window = obs[i+SEQUENCE_SIZE]\n",
    "        window = [[x] for x in window]\n",
    "        #print(\"{} - {}\".format(window,after_window))\n",
    "        x.append(window)\n",
    "        y.append(after_window)\n",
    "        \n",
    "    return np.array(x),np.array(y)\n",
    "    \n",
    "    \n",
    "SEQUENCE_SIZE = 10\n",
    "x_train,y_train = to_sequences(SEQUENCE_SIZE,spots_train)\n",
    "x_test,y_test = to_sequences(SEQUENCE_SIZE,spots_test)\n",
    "\n",
    "print(\"Shape of training set: {}\".format(x_train.shape))\n",
    "print(\"Shape of test set: {}\".format(x_test.shape))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QXxRjf2vnrKC"
   },
   "source": [
    "We can see the internal structure of the training data. The first dimension is the number of training elements, the second indicates a sequence size of 10, and finally, we have one data point per timeslice in the window."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "ckobdirKnD2e",
    "outputId": "7fc5e9c0-e8c0-4f37-cfcc-f25650300118"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(55150, 10, 1)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_train.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "L6_eY2f-nD2e"
   },
   "source": [
    "We are now ready to build and train the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "3whCrzBQnD2e",
    "outputId": "6f19ba11-e8d5-4698-b49c-b99dbb67ecd1"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Build model...\n",
      "Train...\n",
      "Epoch 1/1000\n",
      "1724/1724 - 12s - loss: 1392.9260 - val_loss: 212.4303 - 12s/epoch - 7ms/step\n",
      "Epoch 2/1000\n",
      "1724/1724 - 10s - loss: 516.7653 - val_loss: 239.7139 - 10s/epoch - 6ms/step\n",
      "Epoch 3/1000\n",
      "1724/1724 - 10s - loss: 509.0716 - val_loss: 227.2393 - 10s/epoch - 6ms/step\n",
      "Epoch 4/1000\n",
      "1724/1724 - 10s - loss: 503.2472 - val_loss: 257.9693 - 10s/epoch - 6ms/step\n",
      "Epoch 5/1000\n",
      "1724/1724 - 10s - loss: 498.1863 - val_loss: 226.4870 - 10s/epoch - 6ms/step\n",
      "Epoch 6/1000\n",
      "1724/1724 - 10s - loss: 499.1180 - val_loss: 208.2820 - 10s/epoch - 6ms/step\n",
      "Epoch 7/1000\n",
      "1724/1724 - 10s - loss: 498.4828 - val_loss: 224.2135 - 10s/epoch - 6ms/step\n",
      "Epoch 8/1000\n",
      "1724/1724 - 10s - loss: 497.6813 - val_loss: 253.0776 - 10s/epoch - 6ms/step\n",
      "Epoch 9/1000\n",
      "1724/1724 - 10s - loss: 496.7933 - val_loss: 211.7351 - 10s/epoch - 6ms/step\n",
      "Epoch 10/1000\n",
      "1724/1724 - 10s - loss: 497.0393 - val_loss: 215.1721 - 10s/epoch - 6ms/step\n",
      "Epoch 11/1000\n",
      "Restoring model weights from the end of the best epoch: 6.\n",
      "1724/1724 - 10s - loss: 495.1920 - val_loss: 220.1826 - 10s/epoch - 6ms/step\n",
      "Epoch 11: early stopping\n"
     ]
    }
   ],
   "source": [
    "from tensorflow.keras.preprocessing import sequence\n",
    "from tensorflow.keras.models import Sequential\n",
    "from tensorflow.keras.layers import Dense, Embedding\n",
    "from tensorflow.keras.layers import LSTM\n",
    "from tensorflow.keras.datasets import imdb\n",
    "from tensorflow.keras.callbacks import EarlyStopping\n",
    "import numpy as np\n",
    "\n",
    "print('Build model...')\n",
    "model = Sequential()\n",
    "model.add(LSTM(64, dropout=0.0, recurrent_dropout=0.0,\\\n",
    "                   input_shape=(None, 1)))\n",
    "model.add(Dense(32))\n",
    "model.add(Dense(1))\n",
    "model.compile(loss='mean_squared_error', optimizer='adam')\n",
    "monitor = EarlyStopping(monitor='val_loss', min_delta=1e-3, patience=5, \n",
    "                        verbose=1, mode='auto', restore_best_weights=True)\n",
    "print('Train...')\n",
    "\n",
    "model.fit(x_train,y_train,validation_data=(x_test,y_test),\n",
    "          callbacks=[monitor],verbose=2,epochs=1000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LdKziq28nD2e"
   },
   "source": [
    "Finally, we evaluate the model with RMSE."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "TspuM6gznD2e"
   },
   "outputs": [],
   "source": [
    "from sklearn import metrics\n",
    "\n",
    "pred = model.predict(x_test)\n",
    "score = np.sqrt(metrics.mean_squared_error(pred,y_test))\n",
    "print(\"Score (RMSE): {}\".format(score))"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "colab": {
   "name": "t81_558_class_10_2_lstm.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3.9 (tensorflow)",
   "language": "python",
   "name": "tensorflow"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
